﻿// Gateway.Api 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证（版本 2.0）进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动！任何基于本项目二次开发而产生的一切法律纠纷和责任，我们不承担任何责任！

using Aurora.AI.Abstractions.Chats;
using Aurora.AI.Abstractions.Chats.Dtos;
using Aurora.AI.Domain.Domain.ChatChannel.Aggregates;
using Aurora.AI.Gateway.Services;
using Aurora.AI.Abstractions.Extensions;
using Aurora.AI.Abstractions;
using System.Text;
using Aurora.AI.Abstractions.ObjectModels.RequestModels;
using Aurora.AI.Abstractions.Images;
using Aurora.AI.Abstractions.Images.Dtos;
using Aurora.AI.Common.Constants;
using Aurora.AI.Common.Helper;
using Aurora.AI.Common;
using Aurora.AI.Domain.Domain;
using Aurora.AI.Gateway.Services.ChatChannel;
using System.Diagnostics;
using System.Text.Json;
using Aurora.AI.Abstractions.Dtos;
using Aurora.AI.Abstractions.Embeddings;
using Aurora.AI.Abstractions.ObjectModels.RequestModels.VideoRequestModel;
using Aurora.AI.Abstractions.Video;
using Aurora.AI.Abstractions.Video.Dtos;

namespace Gateway.UI.Api.AiServices.Gateway;

/// <summary>
/// open ai chat service  对话服务
/// </summary>
public class ChatService(
    RateLimitModelService rateLimitModelService,
    ChatChannelService channelService,
    SettingService settingService,
    IRedisCache redisCache,
    ImageService imageService,
    UserAILimitService userService,
    ChatLoggerEventBus eventBus,
    ILogger<ChatService> logger,
    TokenService tokenService)
{
    #region 对话

    /// <summary>
    /// chat completion handle 
    /// </summary>
    /// <param name="context"></param>
    /// <param name="request"></param>
    /// <returns></returns>
    public async ValueTask ChatCompletionHandleAsync(HttpContext context, AuroraAIChatCompletionsRequest request)
    {
        try
        {
            await ChatCompletionsAsync(context, request);
        }
        catch (UnauthorizedAccessException e)
        {
            logger.LogWarning(e,e.Message);
            context.Response.StatusCode = 401;
        }
        catch (Exception e)
        {
            logger.LogError(e.Message);
            if (request.Stream == true)
                await context.WriteStreamErrorAsync(e.Message);
            else
                await context.WriteErrorAsync(e.Message);
        }
    }

    private const string ConsumerTemplate = "模型倍率：{0} 补全倍率：{1}";

    /// <summary>
    /// 对话补全调用
    /// </summary>
    /// <param name="context"></param>
    /// <param name="request"></param>
    /// <returns></returns>
    private async ValueTask ChatCompletionsAsync(HttpContext context, AuroraAIChatCompletionsRequest request)
    {
        // 验证速率
        await rateLimitModelService.CheckAsync(request!.Model, context);

        // 验证用户和额度
        var (token, user) = await tokenService.CheckTokenAsync(context);


        // 获取用户 和 token
        // 获取渠道通过算法计算权重
        var channel = CalculateWeight(await channelService.GetChannelsContainsModelAsync(request.Model));

        if (channel == null)
        {
            throw new ArgumentException(request.Model);
        }

        // 获取渠道指定的实现类型的服务
        var chatCompletionsService =
            context.RequestServices.GetKeyedService<IAuroraAIChatCompletionsService>(channel.Type);

        if (chatCompletionsService == null)
        {
            throw new Exception($"并未实现：{channel.Type} 的服务");
        }

        //todo  获取配置  速率
        var promptRate = await GetPromptRate(request.Model);
        if (promptRate == null)
        {
            context.Response.StatusCode = 200;
            if (request.Stream == true)
                await context.WriteStreamErrorAsync("当前模型未设置倍率");
            else
                await context.WriteErrorAsync("当前模型未设置倍率");
            return;
        }

        // 处理请求数据
        // if (request.WebSearch != null)
        // {
        //     request.Messages = request.Messages.Where(x => !string.IsNullOrWhiteSpace(x.Content)).ToList();
        // }
        // 开始请求
        int requestToken;
        var responseToken = 0;
        if (request.Stream == true)
        {
            (requestToken, responseToken) =
                await StreamChatCompletionsHandlerAsync(context, request, channel, chatCompletionsService,
                    promptRate.Value, user);
        }
        else
        {
            (requestToken, responseToken) =
                await ChatCompletionsHandlerAsync(context, request, channel, chatCompletionsService,
                    promptRate.Value, user);
        }

        var quota = requestToken * promptRate.Value;
        var completionRatio = await GetCompletionRatio(request.Model);
        quota += responseToken * promptRate.Value * completionRatio;

        // 将quota 四舍五入
        quota = Math.Round(quota, 0, MidpointRounding.AwayFromZero);
        //记录日志以及 用户消费
        await eventBus.ConsumeAsync(string.Format(ConsumerTemplate, promptRate.Value, completionRatio),
            request.Model,
            requestToken, responseToken, (int)quota, token?.Name, user?.UserId, user?.UserId, channel.Id,
            channel.Name, context.GetIpAddress(), context.GetUserAgent());

        await userService.ConsumeAsync(user!.UserId, (long)quota, requestToken, token?.Key, channel.Id,
            request.Model);
    }

    /// <summary>
    /// stream chat completion
    /// </summary>
    /// <param name="context"></param>
    /// <param name="input"></param>
    /// <param name="channel"></param>
    /// <param name="openService"></param>
    /// <param name="rate"></param>
    /// <param name="user"></param>
    /// <returns></returns>
    private async Task<(int requestToken, int responseToken)> StreamChatCompletionsHandlerAsync(
        HttpContext context, AuroraAIChatCompletionsRequest input, ChatChannel channel,
        IAuroraAIChatCompletionsService openService,
        decimal rate, UserAILimit user)
    {
        int requestToken;
        var platformOptions = new AuroraAIPlatformOptions(channel.Address, channel.Key, channel.Other);
        var responseMessage = new StringBuilder();
        context.SetEventStreamHeaders();
        if (input.Messages.Any(x => x.Contents != null))
        {
            requestToken = TokenHelper.GetTotalTokens(input?.Messages.Where(x => x.Contents != null)
                .SelectMany(x => x.Contents)
                .Where(x => x.Type == "text").Select(x => x.Text).ToArray());

            requestToken += TokenHelper.GetTotalTokens(input.Messages.Where(x => x.Contents == null)
                .Select(x => x.Content).ToArray());

            // 解析图片
            foreach (var message in input.Messages.Where(x => x is { Contents: not null }).SelectMany(x => x.Contents)
                         .Where(x => x.Type is "image" or "image_url"))
            {
                var imageUrl = message.ImageUrl;
                if (imageUrl != null)
                {
                    var url = imageUrl.Url;
                    var detail = "";
                    if (!imageUrl.Detail.IsNullOrEmpty()) detail = imageUrl.Detail;

                    try
                    {
                        var imageTokens = await CountImageTokens(url, detail);
                        requestToken += imageTokens.Item1;
                    }
                    catch (Exception ex)
                    {
                        logger.LogError("Error counting image tokens: " + ex.Message);
                    }
                }
            }

            var quota = requestToken * rate;
            // 判断请求token数量是否超过额度
            if (quota > user.ResidualCredit)
            {
                throw new ArgumentException("账号余额不足请充值");
            }
        }
        else
        {
            requestToken = TokenHelper.GetTotalTokens(input?.Messages.Select(x => x.Content).ToArray());


            var quota = requestToken * rate;

            // 判断请求token数量是否超过额度
            if (quota > user.ResidualCredit) throw new ArgumentException("账号余额不足请充值");
        }
        // 开始请求

        var circuitBreaker = new CircuitBreaker(3, TimeSpan.FromSeconds(10));
        await circuitBreaker.ExecuteAsync(
            async () =>
            {
                await foreach (var item in openService.StreamChatCompletionsAsync(input, platformOptions))
                {
                    if (item.Error != null)
                    {
                        await context.WriteStreamErrorAsync(item.Error.Message);
                    }
                    else
                    {
                        foreach (var response in item.Choices)
                        {
                            if (response.Delta.Role.IsNullOrEmpty())
                            {
                                response.Delta.Role = "assistant";
                            }

                            if (response.Message.Role.IsNullOrEmpty())
                            {
                                response.Message.Role = "assistant";
                            }

                            if (string.IsNullOrEmpty(response.Delta.Content))
                            {
                                response.Delta.Content = null;
                                response.Message.Content = null;
                            }
                        }
                    }

                    responseMessage.Append(item.Choices?.FirstOrDefault()?.Delta.Content ?? string.Empty);
                    await context.WriteAsEventStreamDataAsync(item).ConfigureAwait(false);
                }
            }, 3, 50);

        await context.WriteAsEventStreamEndAsync();

        var responseToken = TokenHelper.GetTokens(responseMessage.ToString());

        return (requestToken, responseToken);
    }


    /// <summary>
    ///  chat completion
    /// </summary>
    /// <param name="context"></param>
    /// <param name="input"></param>
    /// <param name="channel"></param>
    /// <param name="openService"></param>
    /// <param name="rate"></param>
    /// <param name="user"></param>
    /// <returns></returns>
    private async Task<(int requestToken, int responseToken)> ChatCompletionsHandlerAsync(
        HttpContext context, AuroraAIChatCompletionsRequest input, ChatChannel channel,
        IAuroraAIChatCompletionsService openService,
        decimal rate, UserAILimit user)
    {
        int requestToken;
        int responseToken;
        var platformOptions = new AuroraAIPlatformOptions(channel.Address, channel.Key, channel.Other);
        var responseMessage = new StringBuilder();
        // 这里应该用其他的方式来判断是否是vision模型，目前先这样处理
        if (input.Messages.Any(x => x.Contents != null))
        {
            requestToken = TokenHelper.GetTotalTokens(input?.Messages.Where(x => x.Contents != null)
                .SelectMany(x => x.Contents)
                .Where(x => x.Type == "text").Select(x => x.Text).ToArray());

            requestToken += TokenHelper.GetTotalTokens(input.Messages.Where(x => x.Contents == null)
                .Select(x => x.Content).ToArray());

            // 解析图片
            foreach (var message in input.Messages.Where(x => x is { Contents: not null }).SelectMany(x => x.Contents)
                         .Where(x => x.Type is "image" or "image_url"))
            {
                var imageUrl = message.ImageUrl;
                if (imageUrl != null)
                {
                    var url = imageUrl.Url;
                    var detail = "";
                    if (!imageUrl.Detail.IsNullOrEmpty()) detail = imageUrl.Detail;

                    try
                    {
                        var imageTokens = await CountImageTokens(url, detail);
                        requestToken += imageTokens.Item1;
                    }
                    catch (Exception ex)
                    {
                        logger.LogError("Error counting image tokens: " + ex.Message);
                    }
                }
            }

            var quota = requestToken * rate;
            // 判断请求token数量是否超过额度
            if (quota > user.ResidualCredit)
            {
                throw new ArgumentException("账号余额不足请充值");
            }

            var circuitBreaker = new CircuitBreaker(3, TimeSpan.FromSeconds(10));

            AuroraAIChatCompletionsResponse result = null;

            await circuitBreaker.ExecuteAsync(
                async () => { result = await openService.ChatCompletionsAsync(input, platformOptions); }, 3, 50);

            await context.Response.WriteAsJsonAsync(result);

            responseToken = TokenHelper.GetTokens(result.Choices.FirstOrDefault()?.Delta.Content ?? string.Empty);
        }
        else
        {
            requestToken = TokenHelper.GetTotalTokens(input?.Messages.Select(x => x.Content).ToArray());


            var quota = requestToken * rate;

            // 判断请求token数量是否超过额度
            if (quota > user.ResidualCredit) throw new ArgumentException("账号余额不足请充值");

            var circuitBreaker = new CircuitBreaker(3, TimeSpan.FromSeconds(10));

            AuroraAIChatCompletionsResponse result = null;

            await circuitBreaker.ExecuteAsync(
                async () => { result = await openService.ChatCompletionsAsync(input, platformOptions); }, 3, 50);

            await context.Response.WriteAsJsonAsync(result);

            responseToken = TokenHelper.GetTokens(result.Choices.FirstOrDefault()?.Delta.Content ?? string.Empty);
        }

        return (requestToken, responseToken);
    }

    #endregion

    #region image

    /// <summary>
    /// 图片生成服务
    /// </summary>
    /// <param name="context"></param>
    /// <param name="request"></param>
    /// <returns></returns>
    public async ValueTask CreateImageHandleAsync(HttpContext context, AuroraAIImageCreateRequest request)
    {
        try
        {
            await CreateImageAsync(context, request);
        }
        catch (UnauthorizedAccessException e)
        {
            logger.LogWarning(e,e.Message);
            context.Response.StatusCode = 401;
        }
        catch (Exception e)
        {
            logger.LogError(e.Message);
            await context.WriteErrorAsync(e.Message);
        }
    }

    /// <summary>
    /// create image 图片生成服务
    /// </summary>
    /// <param name="context"></param>
    /// <param name="request"></param>
    /// <returns></returns>
    private async ValueTask CreateImageAsync(HttpContext context, AuroraAIImageCreateRequest request)
    {
        if (request == null) throw new ArgumentException("模型校验异常");

        var (token, user) = await tokenService.CheckTokenAsync(context);

        if (request?.Model.IsNullOrEmpty() == true) request.Model = "dall-e-2";
        await rateLimitModelService.CheckAsync(request.Model, context);
        var imageCostRatio = await GetImageCostRatio(request);
        var rate = (await GetPromptRate(request.Model)) ?? 1;
        request.N ??= 1;
        var quota = (int)(rate * imageCostRatio * 1000) * request.N;
        if (quota > user.ResidualCredit) throw new ArgumentException("账号余额不足请充值");
        // 获取渠道 通过算法计算权重
        var channel = CalculateWeight(await channelService.GetChannelsContainsModelAsync(request.Model));
        if (channel == null) throw new ArgumentException("未找到可用渠道");

        // 获取渠道指定的实现类型的服务
        var openService = context.RequestServices.GetKeyedService<IAuroraAIImageService>(channel.Type);
        if (openService == null) throw new ArgumentException($"并未实现：{channel.Type} 的服务");
        var response = await openService.CreateImage(request, new AuroraAIPlatformOptions
        {
            ApiKey = channel.Key,
            Address = channel.Address,
            Other = channel.Other
        }, context.RequestAborted);
        await context.Response.WriteAsJsonAsync(new AuroraAIImageCreateResponse
        {
            data = response.Results,
            created = response.CreatedAt,
            successful = response.Successful,
            message = string.Join(",", response.Error?.Messages ?? new List<string>())
        });
        await eventBus.ConsumeAsync(string.Format(ConsumerTemplate, rate, 0), request.Model,
            0, 0, quota ?? 0, token?.Name, user?.UserId, user?.UserId, channel.Id,
            channel.Name, context.GetIpAddress(), context.GetUserAgent());

        await userService.ConsumeAsync(user!.UserId, quota ?? 0, 0, token?.Key, channel.Id, request.Model);
    }

    #endregion

    #region embeddings

    /// <summary>
    /// embeddings
    /// </summary>
    /// <param name="context"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentException"></exception>
    public async ValueTask EmbeddingAsync(HttpContext context)
    {
        try
        {
            using var body = new MemoryStream();
            await context.Request.Body.CopyToAsync(body);

            var module = System.Text.Json.JsonSerializer.Deserialize<AuroraAIEmbeddingInput>(body.ToArray());

            if (module == null) throw new Exception("模型校验异常");

            await rateLimitModelService.CheckAsync(module!.Model, context);

            var (token, user) = await tokenService.CheckTokenAsync(context);

            // 获取渠道 通过算法计算权重
            var channel = CalculateWeight(await channelService.GetChannelsContainsModelAsync(module.Model));

            if (channel == null) throw new ArgumentException(module.Model);

            // 获取渠道指定的实现类型的服务
            var embeddingService = context.RequestServices.GetKeyedService<IAuroraAITextEmbeddingService>(channel.Type);

            if (embeddingService == null) throw new Exception($"并未实现：{channel.Type} 的服务");

            var embeddingCreateRequest = new EmbeddingCreateRequest
            {
                Model = module.Model,
                EncodingFormat = module.EncodingFormat
            };

            int requestToken;
            if (module.Input is JsonElement str)
            {
                if (str.ValueKind == JsonValueKind.String)
                {
                    embeddingCreateRequest.Input = str.ToString();
                    requestToken = TokenHelper.GetTotalTokens(str.ToString());
                }
                else if (str.ValueKind == JsonValueKind.Array)
                {
                    var inputString = str.EnumerateArray().Select(x => x.ToString()).ToArray();
                    embeddingCreateRequest.InputAsList = inputString.ToList();
                    requestToken = TokenHelper.GetTotalTokens(inputString);
                }
                else
                {
                    throw new Exception("输入格式错误");
                }
            }
            else
            {
                throw new Exception("输入格式错误");
            }

            var sw = Stopwatch.StartNew();

            var stream = await embeddingService.EmbeddingAsync(embeddingCreateRequest, new AuroraAIPlatformOptions
            {
                ApiKey = channel.Key,
                Address = channel.Address,
                Other = channel.Other
            }, context.RequestAborted);
            sw.Stop();
            //todo  获取配置  速率
            var promptRate = await GetPromptRate(module.Model);
            if (promptRate == null)
            {
                context.Response.StatusCode = 200;
                await context.WriteErrorAsync("当前模型未设置倍率");
                return;
            }

            var quota = requestToken * promptRate.Value;

            var completionRatio = await GetCompletionRatio(module.Model);
            quota += promptRate.Value * completionRatio;

            // 将quota 四舍五入
            quota = Math.Round(quota, 0, MidpointRounding.AwayFromZero);

            await eventBus.ConsumeAsync(string.Format(ConsumerTemplate, promptRate.Value, completionRatio),
                module.Model,
                requestToken, 0, (int)quota, token?.Name, user?.UserId, user?.UserId, channel.Id,
                channel.Name, context.GetIpAddress(), context.GetUserAgent());

            await userService.ConsumeAsync(user!.Id, (long)quota, requestToken, token?.Key, channel.Id,
                module.Model);


            await context.Response.WriteAsJsonAsync(stream);
        }

        catch (UnauthorizedAccessException e)
        {
            logger.LogWarning(e,e.Message);
            context.Response.StatusCode = 401;
        }
        catch (Exception e)
        {
            logger.LogError(e, e.Message);

            await context.WriteErrorAsync(e.Message);
        }
    }

    #endregion

    #region common

    /// <summary>
    /// 计算图片倍率
    /// </summary>
    /// <param name="module"></param>
    /// <returns></returns>
    private async Task<decimal> GetImageCostRatio(AuroraAIImageCreateRequest module)
    {
        var imageCostRatio = await GetImageSizeRatio(module.Model, module.Size);
        if (module is { Quality: "hd", Model: "dall-e-3" })
        {
            if (module.Size == "1024x1024")
                imageCostRatio *= 2;
            else
                imageCostRatio *= (decimal)1.5;
        }

        return imageCostRatio;
    }

    /// <summary>
    /// 计算图片倍率
    /// </summary>
    /// <param name="model"></param>
    /// <param name="size"></param>
    /// <returns></returns>
    public async Task<decimal> GetImageSizeRatio(string model, string size)
    {
        var data = await settingService.GetImageSizeRatios();
        if (!data.TryGetValue(model, out var ratios)) return 1;

        if (ratios.TryGetValue(size, out var ratio)) return (decimal)ratio;

        return 1;
    }


    /// <summary>
    /// 计算图片token
    /// </summary>
    /// <param name="url"></param>
    /// <param name="detail"></param>
    /// <returns></returns>
    public async ValueTask<Tuple<int, Exception>> CountImageTokens(string url, string detail)
    {
        var fetchSize = true;
        int width = 0, height = 0;
        var lowDetailCost = 20; // Assuming lowDetailCost is 20
        var highDetailCostPerTile = 100; // Assuming highDetailCostPerTile is 100
        var additionalCost = 50; // Assuming additionalCost is 50

        if (string.IsNullOrEmpty(detail) || detail == "auto") detail = "high";

        switch (detail)
        {
            case "low":
                return new Tuple<int, Exception>(lowDetailCost, null);
            case "high":
                if (fetchSize)
                    try
                    {
                        (width, height) = await imageService.GetImageSize(url);
                    }
                    catch (Exception e)
                    {
                        return new Tuple<int, Exception>(0, e);
                    }

                if (width > 2048 || height > 2048)
                {
                    var ratio = 2048.0 / Math.Max(width, height);
                    width = (int)(width * ratio);
                    height = (int)(height * ratio);
                }

                if (width > 768 && height > 768)
                {
                    var ratio = 768.0 / Math.Min(width, height);
                    width = (int)(width * ratio);
                    height = (int)(height * ratio);
                }

                var numSquares = (int)Math.Ceiling((double)width / 512) * (int)Math.Ceiling((double)height / 512);
                var result = numSquares * highDetailCostPerTile + additionalCost;
                return new Tuple<int, Exception>(result, null);
            default:
                return new Tuple<int, Exception>(0, new Exception("Invalid detail option"));
        }
    }

    /// <summary>
    /// 对话模型补全倍率
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    private async Task<decimal> GetCompletionRatio(string name)
    {
        var rate = await GetCompletionRate(name);
        if (rate != null) return rate.Value;

        if (name.StartsWith("gpt-3.5"))
        {
            if (name == "gpt-3.5-turbo" || name.EndsWith("0125")) return 3;

            if (name.EndsWith("1106")) return 2;

            return (decimal)(4.0 / 3.0);
        }

        if (name.StartsWith("gpt-4")) return name.StartsWith("gpt-4-turbo") ? 3 : 2;

        if (name.StartsWith("claude-")) return name.StartsWith("claude-3") ? 5 : 3;

        if (name.StartsWith("mistral-") || name.StartsWith("gemini-")) return 3;

        return name switch
        {
            "llama2-70b-4096" => new decimal(0.8 / 0.7),
            _ => 1
        };
    }


    /// <summary>
    /// 获取速率
    /// </summary>
    /// <param name="model"></param>
    /// <returns></returns>
    private async Task<decimal?> GetPromptRate(string model)
    {
        var data = await redisCache.GetAsync<Dictionary<string, decimal>>(CacheConstant.PromptRateCacheKey);
        if (data == null)
        {
            data = await settingService.GetPromptRate();
            await redisCache.AddAsync(CacheConstant.PromptRateCacheKey, data, TimeSpan.FromHours(24));
        }

        if (data == null)
        {
            throw new ArgumentException("未配置模型速率");
        }

        var success = data.TryGetValue(model, out var rate);

        return success ? rate : null;
    }

    /// <summary>
    /// 获取速率
    /// </summary>
    /// <param name="model"></param>
    /// <returns></returns>
    private async Task<decimal?> GetCompletionRate(string model)
    {
        var data = await redisCache.GetAsync<Dictionary<string, decimal>>(CacheConstant.CompletionRateCacheKey);
        if (data == null)
        {
            data = await settingService.GetCompletionRate();
            await redisCache.AddAsync(CacheConstant.CompletionRateCacheKey, data, TimeSpan.FromHours(24));
        }

        if (data == null)
            return null;
        var success = data.TryGetValue(model, out var rate);
        return success ? rate : null;
    }

    /// <summary>
    /// 权重算法
    /// </summary>
    /// <param name="channel"></param>
    /// <returns></returns>
    private static ChatChannel CalculateWeight(IEnumerable<ChatChannel> channel)
    {
        var chatChannels = channel.ToList();
        if (chatChannels.Count == 0)
        {
            throw new ArgumentException("模型未找到可用的渠道");
        }

        // 所有权重值之和
        var total = chatChannels.Sum(x => x.Order);

        var value = Convert.ToInt32(Random.Shared.NextDouble() * total);

        foreach (var chatChannel in chatChannels)
        {
            value -= chatChannel.Order;
            if (value <= 0)
            {
                return chatChannel;
            }
        }

        return chatChannels.Last();
    }

    #endregion


    #region video

    // 生成任务
    /// <summary>
    /// video 生成任务
    /// </summary>
    /// <param name="context"></param>
    /// <param name="request"></param>
    /// <returns></returns>
    public async ValueTask CreateVideoTaskHandleAsync(HttpContext context, VideoCreateRequest request)
    {
        try
        {
            await CreateVideoTaskAsync(context, request);
        }
        catch (UnauthorizedAccessException e)
        {
            logger.LogWarning(e, "认证失败" + e.Message);
            context.Response.StatusCode = 401;
        }
        catch (Exception e)
        {
            logger.LogError(e.Message);
            await context.WriteErrorAsync(e.Message);
        }
    }

    /// <summary>
    /// video 查询任务
    /// </summary>
    /// <param name="context"></param>
    /// <param name="request"></param>
    /// <returns></returns>
    public async ValueTask QueryVideoTaskHandleAsync(HttpContext context, VideoTaskQueryRequest request)
    {
        try
        {
            await QueryVideoTaskAsync(context, request);
        }
        catch (UnauthorizedAccessException e)
        {
             logger.LogError(e,e.Message);
            context.Response.StatusCode = 401;
        }
        catch (Exception e)
        {
            logger.LogError(e.Message);
            await context.WriteErrorAsync(e.Message);
        }
    }
    // 查询任务


    private async Task CreateVideoTaskAsync(HttpContext context, VideoCreateRequest request)
    {
        if (request == null) throw new ArgumentException("模型校验异常");

        var (token, user) = await tokenService.CheckTokenAsync(context);

        if (request?.Model.IsNullOrEmpty() == true) request.Model = "dall-e-2";
        await rateLimitModelService.CheckAsync(request.Model, context);


        var rate = (await GetPromptRate(request.Model)) ?? 1;


        var completionRatio = await GetCompletionRatio(request.Model);
        var quota = 1 * rate * completionRatio;

        // 将quota 四舍五入
        quota = Math.Round(quota, 0, MidpointRounding.AwayFromZero);


        if (rate > user.ResidualCredit) throw new ArgumentException("账号余额不足请充值");
        // 获取渠道 通过算法计算权重
        var channel = CalculateWeight(await channelService.GetChannelsContainsModelAsync(request.Model));
        if (channel == null) throw new ArgumentException("未找到可用渠道");

        // 获取渠道指定的实现类型的服务
        var openService = context.RequestServices.GetKeyedService<IAuroraVideoService>(channel.Type);
        if (openService == null) throw new ArgumentException($"并未实现：{channel.Type} 的服务");
        var response = await openService.CreateVideoTask(request, new AuroraAIPlatformOptions
        {
            ApiKey = channel.Key,
            Address = channel.Address,
            Other = channel.Other
        }, context.RequestAborted);
        await context.Response.WriteAsJsonAsync(new AuroraVideoCreateResponse()
        {
            data = response.Id,
            created = 0,
            successful = response.Successful,
            status = response.TaskStatus,
            message = string.Join(",", response.Error?.Messages ?? new List<string>())
        });
        await eventBus.ConsumeAsync(string.Format(ConsumerTemplate, rate, 0), request.Model,
            0, 0, (int)quota, token?.Name, user?.UserId, user?.UserId, channel.Id,
            channel.Name, context.GetIpAddress(), context.GetUserAgent());

        await userService.ConsumeAsync(user!.UserId, (long)quota, 0, token?.Key, channel.Id, request.Model);
    }


    private async Task QueryVideoTaskAsync(HttpContext context, VideoTaskQueryRequest request)
    {
        if (request == null) throw new ArgumentException("模型校验异常");

        // 获取渠道 通过算法计算权重
        var channel = CalculateWeight(await channelService.GetChannelsContainsModelAsync(request.Model));
        if (channel == null) throw new ArgumentException("未找到可用渠道");

        // 获取渠道指定的实现类型的服务
        var openService = context.RequestServices.GetKeyedService<IAuroraVideoService>(channel.Type);
        if (openService == null) throw new ArgumentException($"并未实现：{channel.Type} 的服务");
        var response = await openService.QueryVideoTask(request, new AuroraAIPlatformOptions
        {
            ApiKey = channel.Key,
            Address = channel.Address,
            Other = channel.Other
        }, context.RequestAborted);
        await context.Response.WriteAsJsonAsync(new AuroraVideoCreateResponse()
        {
            data = response.Results,
            created = 0,
            successful = response.Successful,
            status = response.TaskStatus,
            message = string.Join(",", response.Error?.Messages ?? new List<string>())
        });
    }

    #endregion
}